import datetime
import io
import json
import os
import time
from typing import Union, Annotated, List
from fastapi import APIRouter, Query, Depends, BackgroundTasks
from fastapi.responses import StreamingResponse, FileResponse
from pydantic import BaseModel
import asyncio

from log.logger import logger_time
from .DockedTime import DockedTime
from .ShipInfo import ShipInfo
from .SpeedInterval import SpeedInterval
from .PlotRoute import PlotRoute
from .PDFMaker import PDFMaker

router = APIRouter(prefix="/speed_interval")
dockedTime = DockedTime()


class SpeedIntervalQuery(BaseModel):
    mmsi: int
    startSpeed: int = 8


class SpeedIntervalInfo(BaseModel):
    startSpeed: int
    endSpeed: int
    totalSecond: int
    rate: float


class DockedInfo(BaseModel):
    portId: int
    portName: str
    lat: float
    lon: float
    totalSeconds: int


class TimeDict(BaseModel):
    total: float
    requests: float
    calInterval: float
    calDocker: float


class SpeedIntervalResponse(BaseModel):
    mmsi: int
    records: int
    infoList: List[SpeedIntervalInfo]
    dockedList: List[DockedInfo]
    timeDict: TimeDict


async def get_data(mmsi: Annotated[int, Query(description="船舶的mmsi编号")],
                   timeInterval: Annotated[Union[datetime.timedelta, None], Query(description="间隔时间")] = None,
                   startTime: Annotated[Union[datetime.datetime, None], Query(description="起始时间")] = None,
                   endTime: Annotated[Union[datetime.datetime, None], Query(description="结束时间")] = None,
                   concurrency: Annotated[int, Query(ge=1, description="请求上游数据的并发度", le=16)] = 4):
    si = ShipInfo(mmsi, timeInterval, startTime, endTime)
    start_time = datetime.datetime.now()
    task1 = asyncio.create_task(si.get_data_parallel(concurrency))
    task2 = asyncio.create_task(si.get_highest_level())
    ship_info_list = await task1
    await task2
    seconds = (datetime.datetime.now() - start_time).total_seconds()
    return mmsi, si.records, ship_info_list, si.highest_level, {"total": seconds, "requests": seconds}


async def calculate(result: Annotated[tuple, Depends(get_data)],
                                   startSpeed: Annotated[int, Query(description="统计的最低速度")] = 8):
    mmsi, records, ship_info_list, highest_level, timeDict = result
    start_time = datetime.datetime.now()
    interval_result = SpeedInterval.analysis(highest_level, startSpeed, ship_info_list)
    seconds = (datetime.datetime.now() - start_time).total_seconds()
    timeDict.update(calInterval=seconds, total=timeDict["total"]+seconds)

    start_time = datetime.datetime.now()
    docker_result = await dockedTime.get_docker_info_format([x[:3] for x in ship_info_list] if ship_info_list else [])
    seconds = (datetime.datetime.now() - start_time).total_seconds()
    timeDict.update(calDocker=seconds, total=timeDict["total"]+seconds)
    return ship_info_list, {
        "mmsi": mmsi,
        "records": records,
        "infoList": interval_result,
        "dockedList": docker_result,
        "timeDict": timeDict
    }


async def plot(result: Annotated[tuple, Depends(calculate)]):
    ship_info_list, d = result

    start_time = datetime.datetime.now()
    pr = PlotRoute()
    file_path = pr.make_plot(ship_info_list, d["dockedList"])
    seconds = (datetime.datetime.now() - start_time).total_seconds()
    d["timeDict"].update(plot=seconds, total=d["timeDict"]["total"]+seconds)

    return file_path, d


async def make_pdf(result: Annotated[tuple, Depends(plot)]):
    file_path, d = result

    start_time = datetime.datetime.now()
    pdf_path = PDFMaker.make_pdf(d, file_path)
    seconds = (datetime.datetime.now() - start_time).total_seconds()
    d["timeDict"].update(pdf=seconds, total=d["timeDict"]["total"]+seconds)

    return pdf_path, file_path, d


@router.get("/get", response_model=SpeedIntervalResponse, description="获取指定船舶在指定时间内的统计数据")
async def get_ship_speed_intervals(result: Annotated[tuple, Depends(calculate)]):
    _, d = result
    logger_time.info("request path: /get, record processed: " + str(d["records"]) + ", cost time: " + str(d["timeDict"]))
    return d


async def remove_file(file_path):
    await asyncio.sleep(60)
    os.remove(file_path)


@router.get("/get_img", description="获取统计数据的同时将航线绘图,统计数据在headers.info中")
async def get_ship_speed_intervals(result: Annotated[tuple, Depends(plot)], backgroundTask: BackgroundTasks):
    file_path, d = result

    file = open(file_path, mode="rb")
    stream = io.BytesIO(file.read())
    file.close()
    backgroundTask.add_task(remove_file, file_path)

    logger_time.info("request path: /get_img, record processed: " + str(d["records"]) + ", cost time: " + str(d["timeDict"]))

    return StreamingResponse(stream, media_type="image/png", headers={"info": json.dumps(d)})


@router.get("/get_pdf", description="获取包含所有信息的pdf")
async def get_pdf(result: Annotated[tuple, Depends(make_pdf)], backgroundTask: BackgroundTasks):
    pdf_file_path, img_file_path, d = result

    backgroundTask.add_task(remove_file, pdf_file_path)
    backgroundTask.add_task(remove_file, img_file_path)

    logger_time.info("request path: /get_pdf, record processed: " + str(d["records"]) + ", cost time: " + str(d["timeDict"]))

    filename = str(d["mmsi"]) + "_" + str(int(time.time()*1000)) + "_Report.pdf"

    return FileResponse(pdf_file_path, headers={"info": json.dumps(d)}, filename=filename)

